package com.aispeech.astools.recorder;

import android.app.Application;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import com.aispeech.astools.recorder.RecordListener.EVENT;
import com.aispeech.astools.utils.AudioRecordConfig;
import com.aispeech.astools.utils.AudioRecordUtils;


public class UacRecord implements BaseRecord {

    private final static String TAG = "UacRecord";

    //    private Application mContext;
    private RecordListener mListener;

    private static boolean isRecording = false;
    private int resetTimes = 60;

    private static HandlerThread recordThread;

    private Handler recordHandler;
    private static final int RECORD_CTRL_READ = 0x1;

    private AudioRecord recorder;

    AudioRecordConfig getAudioRecordConfig() {
        AudioRecordConfig aconfig = new AudioRecordConfig();
        aconfig.setChannel(AudioFormat.CHANNEL_IN_MONO);
//        aconfig.setChannel(AudioFormat.CHANNEL_IN_STEREO);
        aconfig.setEncoding(AudioFormat.ENCODING_PCM_16BIT);
        aconfig.setSource(MediaRecorder.AudioSource.MIC);
        aconfig.setReadBufIntervalTime(48);
        aconfig.setSample(16000);
        return aconfig;
    }

    private void createRecordHandler() {
        Log.d(TAG, "createRecordHandler: ");
        recordHandler = new Handler(recordThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);

                Log.d(TAG, "handleMessage: recordThread.getId = " + recordThread.getId());
                String err = null;

                int read_buf_len = AudioRecordUtils.getReadByteBufferSize(getAudioRecordConfig());
                byte[] readBuffer = new byte[read_buf_len];
                isRecording = true;

                if (recorder == null) {
                    try {
                        recorder = AudioRecordUtils.newInstance(getAudioRecordConfig());
                        Log.w(TAG, "new AudioRecord ----------------- ");
                        if (null == recorder) {
                            err = "recorder start failed, recorder is null";
                        } else {
                            recorder.startRecording();
                            Log.w(TAG, "startRecording AudioRecord ----------------- ");

                            if (recorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
                                err = "recorder start failed, state: " + recorder.getRecordingState();
                            }
                        }
                    } catch (Exception e) {
                        err = "recorder start failed, exception: " + e.getMessage();
                    }
                }

                if (TextUtils.isEmpty(err) && recorder != null) {
                    mListener.onEvent(EVENT.START);

//                    feedFromFile();
                    Log.d(TAG, "handleMessage: start read -----------------------");

                    while (isRecording && TextUtils.isEmpty(err)) {
//                        Log.d(TAG, "handleMessage: read before -----------------------");

                        int size = recorder.read(readBuffer, 0, read_buf_len);
//                        Log.d(TAG, "handleMessage: read after -----------------------");

                        if (size == readBuffer.length) {
//                                    final byte[] publishBuffer = Arrays.copyOfRange(readBuffer, 0, size);
//                                    final byte[] bytes = new byte[size];
//                                    System.arraycopy(readBuffer, 0, bytes, 0, size);

//                            feedBuf(readBuffer);
                            mListener.onBuffer(readBuffer);
                        } else {
                            err = "recorder read failed - size: " + size;
                        }
                    }
                    Log.d(TAG, "handleMessage: isRecording = " + isRecording);
                }

                if (recorder != null) {
                    try {
                        recorder.stop();
                        recorder.release();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        Log.w(TAG, "stop and release recorder in finally , err = " + err + " thread id = " + recordThread.getId());
                        mListener.onEvent(EVENT.STOP);
                        recorder = null;
                    }
                }

                if (!TextUtils.isEmpty(err)) {
                    Log.e(TAG, "<><><>--- recorder on error: " + err + " thread id = " + recordThread.getId());
                    Log.e(TAG, "<><><>--- recorder on isRecording: " + isRecording + " resetTimes = " + resetTimes);
//                    mListener.onEvent(mUdev, EventType.RUN_AUDIO_RECORD_ERR, err);
                    if (((resetTimes--) > 0) && isRecording && (null != recordHandler)) {
                        Log.e(TAG, "<><><>--- RECORD_CTRL_READ delay 1200 ms " + " thread id = " + recordThread.getId());
                        recordHandler.sendEmptyMessageDelayed(RECORD_CTRL_READ, 1200);
                    }
                    mListener.onError(err);
                }

                //make isRecording false only in stop method
//                isRecording = false;
            }
        };
    }

//    private void feedFromFile() {
//        Log.d(TAG, "feedFromFile");
//        try {
//
//            String audioOnBufPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "feedbuf.wav";
//            Log.d(TAG, "feedFromFile audioOnBufPath = " + audioOnBufPath);
//            FileInputStream fin = new FileInputStream(new File(audioOnBufPath));
//            byte[] audioData = new byte[fin.available()];
//            Log.d(TAG, "feedFromFile audioData len = " + audioData.length);
//            fin.read(audioData);
//            fin.close();
//
//            byte[] bufferData = Arrays.copyOfRange(audioData, 44, audioData.length);
//            Log.d(TAG, "feedFromFile bufferData len = " + bufferData.length);
//
//            for (int i = 0; i <= (bufferData.length - 3072); i += 3072) {
//
//                byte[] destBytes = new byte[3072];
//                System.arraycopy(bufferData, i, destBytes, 0, 3072);
//                feedBuf(destBytes);
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        isRecording = false;
//    }

    public void init(Application appContext, RecordListener listener) {
        Log.d(TAG, "UacRecord: init");

//        mContext = appContext;
        mListener = listener;
        recordThread = new HandlerThread("UacRecordThread", Thread.MAX_PRIORITY);
        recordThread.start();
        createRecordHandler();
    }

    /**
     * 开始录音
     */
    public void start() {
        start(0);
    }

    /**
     * 延时delay毫秒后再开启录音
     *
     * @param delay 延时毫秒
     */
    public void start(int delay) {
        Log.d(TAG, "start with: delay = " + delay + "");

        if (isRecording) {
            Log.w(TAG, "start: Already Recording !");
            return;
        }
        if (null == recordHandler) {
            Log.e(TAG, "start record err, the mListener or recordHandler or mUdev is null !");
            return;
        }

        resetTimes = 60;
        recordHandler.sendEmptyMessageDelayed(RECORD_CTRL_READ, delay);
    }

    /**
     * 停止录音
     */
    public void stop() {
        Log.d(TAG, "stop: ");
        if (null != recordHandler) {
            recordHandler.removeMessages(RECORD_CTRL_READ);
        }
        isRecording = false;
    }

    public void destroy() {
        Log.d(TAG, "destroy: ");
        stop();

        if (null != mListener) {
            mListener.onEvent(EVENT.DESTROY);
        }

        if (null != recordHandler) {
            recordHandler.removeCallbacksAndMessages(null);
            recordHandler = null;
        }

        if (null != recordThread) {
            recordThread.quit();
        }

        if (null != recorder) {
            recorder.stop();
            recorder.release();
        }
    }

    public boolean isRecording() {
        return isRecording;
    }

}
